package uk.co.davedexter.flickrdatr;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import com.aetrion.flickr.Flickr;
import com.aetrion.flickr.FlickrException;
import com.aetrion.flickr.REST;
import com.aetrion.flickr.RequestContext;
import com.aetrion.flickr.auth.Auth;
import com.aetrion.flickr.auth.AuthInterface;
import com.aetrion.flickr.auth.Permission;
import com.aetrion.flickr.people.User;
import com.aetrion.flickr.photos.Exif;
import com.aetrion.flickr.photos.Photo;
import com.aetrion.flickr.photos.PhotoList;
import com.aetrion.flickr.photos.PhotosInterface;
import com.aetrion.flickr.photos.SearchParameters;
import com.aetrion.flickr.photosets.Photoset;
import com.aetrion.flickr.photosets.PhotosetsInterface;
import com.aetrion.flickr.tags.Tag;
import com.aetrion.flickr.uploader.Uploader;
import com.aetrion.flickr.util.FileAuthStore;

public class FlickrDatr {

	private Flickr flickr;
	private FileAuthStore store;
	AuthInterface authInterface;
	Auth auth;
	private static String apiKey = "45bc65fa6dc96825653b96e5333d0072";
	private static String secret = "a0c74b31cbde681d";
	private String nSID;
	private PhotosInterface photoInt;
	private DateFormat df;
	private DateFormat flickrDf;
	private DateFormat titleDf;

	
	private static String photoLocation = "/media/1-5_DAS/photos";

	FlickrDatr(String nSID) {
		this.nSID = nSID;
		df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		flickrDf = new SimpleDateFormat("yyyy:MM:dd hh:mm:ss");
		titleDf = new SimpleDateFormat("yyyy-MM-dd hh:mm");


		// Set up the flickr connection
		try {
			flickr = new Flickr(apiKey, secret, new REST());
			authInterface = flickr.getAuthInterface();

			RequestContext rc = RequestContext.getRequestContext();

			File authDir = new File("authstore");
			if (authDir.exists() & authDir.isDirectory()) {
				System.out.println("Loading existing authorisation.");
				store = new FileAuthStore(authDir);
				auth = store.retrieve(nSID);
				rc.setAuth(auth);
			} else {
				// Prompt the user.
				String frob = authInterface.getFrob();
				URL url = authInterface.buildAuthenticationUrl(Permission.WRITE, frob);
				System.out.println("Press return after you granted access at this URL:");
				System.out.println(url.toExternalForm());
				BufferedReader infile = new BufferedReader(new InputStreamReader(System.in));
				infile.readLine();
				auth = authInterface.getToken(frob);

				rc.setAuth(auth);

				store = new FileAuthStore(new File("authstore"));
				store.store(auth);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (FlickrException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
	}

	private void processAllFiles() {
		try {
			photoInt = flickr.getPhotosInterface();
			SearchParameters searchParams = new SearchParameters();
			searchParams.setMedia("photos");
			searchParams.setUserId(nSID);
//			searchParams.setText("2011.01.14");
//			searchParams.setText("2011-04-11*");
//			searchParams.setText("pumpkin");

			ArrayList<String> incomplete = new ArrayList<String>();
			
			int processCount = 0;
			long startTime = System.currentTimeMillis();
			
			int i = 0;
			int size = 500;
			while (size == 500) {
				PhotoList results = photoInt.search(searchParams, 500, i);
				size = results.size();
				i++;

				Iterator<Photo> itr = results.iterator();
				while (itr.hasNext()) {
					
					processCount++;
					if (processCount % 10 == 0) {
						System.out.printf("\nProcessed %s files in %ss.\n\n", processCount, (System.currentTimeMillis() - startTime)/1000);
					}
					
					Photo p = itr.next();
					String createDate = "";
					boolean preventProcessing = false;
					
					ArrayList<String> tags = readTags(p);
					System.out.println(p.getTitle() + "\t" + tags);
					
					if (!tags.contains("Dated")) {
						String imageFileName = getImageFileName(p);
						HashMap exif = getExif(p);
						if (exif.containsKey("CreateDate")) {
							createDate = (String)exif.get("CreateDate");
						} else {
							System.out.println("\tCannot find create date, looking for RAW image on disk.");
							String path = photoLocation;
							for (String tag : tags) {
								path += "/" + tag;
							}
							path = path.replace("/Automatically Uploaded", "").replace("/JPEG", "");
							File lc = new File(path + "/" + imageFileName.replace(".cr2.jpg", ".cr2"));
							File uc = new File(path + "/" + imageFileName.replace(".cr2.jpg", ".CR2"));
							File raw = null;
							if (lc.exists()) { raw = lc; }
							if (uc.exists()) { raw = uc; }
							if (raw == null) {
								preventProcessing = true;
								incomplete.add(p.getTitle() + ";" + tags.toString());
								System.out.println("\t***Adding to incomplete. Cannot find RAW image: " + p.getTitle() + ";" + tags.toString());
							} else if (!getExtension(raw).toLowerCase().equals("cr2")) { 
								preventProcessing = true;
								incomplete.add(p.getTitle() + ";" + tags.toString());
								System.out.println("\t***Adding to incomplete. Original image is not a RAW image: " + p.getTitle() + ";" + tags.toString());
							} else {
								System.out.println("\tGetting create date from original RAW file: " + raw);
								try {
					                Runtime rt = Runtime.getRuntime();
					                Process pr = rt.exec("identify -verbose " + raw.toString());
					                BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
					                String line=null;
					 
					                while((line=input.readLine()) != null) {
					                    if (line.contains("exif:DateTime:")) {
					                    	createDate = line.replace("exif:DateTime: ", "").trim();
					                    }
					                }
					 
					                int exitVal = pr.waitFor();
//					                System.out.println("\t\tExited with error code "+exitVal);
					 
					            } catch(Exception e) {
					                e.printStackTrace();
					            }
					            
							}
						}
						
						System.out.println("\tCreate Date: " + createDate);
						System.out.println("\tImage filename: " + imageFileName);
						
						// Check createDate is later than my Flickr joining date.
						Date dateCreated = new Date();
						Date dateJoined = new Date();
						Date datePosted = new Date();
						try {
							dateCreated = flickrDf.parse(createDate);
							dateJoined = df.parse("2010-02-05 00:00:00");
							datePosted = dateCreated;
							if (dateCreated.before(dateJoined)) {
								datePosted = df.parse("2010-02-05 00:00:00");
							}
						} catch (ParseException e) {
							System.out.println("\tUnable to parse the createDate. Skipping processing.");
							incomplete.add(p.getTitle() + ";" + tags.toString());
							preventProcessing = true;
						}
						
						// Write information back to flickr photo.
						if (!preventProcessing) {
							writeDataToPhoto(p, datePosted, dateCreated, imageFileName);
						} else {
							System.out.println("\tNot updating details.");
						}
					}
					
					
				}
			}
			
			// Print those files that couldn't be processed.
			System.out.println("\nUnprocessed files:");
			for (String file : incomplete) {
				System.out.println(file);
			}

		} catch (FlickrException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		}
	}
	
	private ArrayList<String> readTags(Photo p) throws IOException, SAXException, FlickrException {
		Photo photo = photoInt.getInfo(p.getId(), p.getSecret());
		ArrayList<String> tags = new ArrayList<String>();
		Collection tagsCol = photo.getTags();
		Iterator itr = tagsCol.iterator();
		while (itr.hasNext()) {
			Tag tag = (Tag)itr.next();
			tags.add(tag.getRaw());
		}
		return tags;
	}
	
	private String getExtension(File file) {
		int dotPos = file.toString().lastIndexOf(".");
        return file.toString().substring(dotPos);
	}
	
	private String getImageFileName(Photo p) {
		Pattern r = Pattern.compile("^\\d+\\. (.*)");
		Matcher m = r.matcher(p.getTitle());
		if (m.find()) {
			return m.group(1);
		} else {
			Pattern r1 = Pattern.compile("^\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d\\. (.*)");
			Matcher m1 = r1.matcher(p.getTitle());
			if (m1.find()) {
				return m1.group(1);
			} else {
				return p.getTitle();
			}
		}
	}
	
	private HashMap getExif(Photo p) throws IOException, SAXException, FlickrException {
		HashMap exifMap = new HashMap();
		Collection exifCollection = photoInt.getExif(p.getId(), p.getSecret());
		Iterator itr = exifCollection.iterator();
		while (itr.hasNext()) {
			Exif exif = (Exif) itr.next();
			exifMap.put(exif.getTag(), exif.getRaw());
		}
		return exifMap;
	}
	
	private void writeDataToPhoto(Photo p, Date postedDate, Date createDate, String imageName) throws IOException, SAXException, FlickrException {
		System.out.println("\tWriting data back to file.");
		String title = titleDf.format(createDate) + ". " + imageName;
		System.out.println("\t\tSetting title: " + title);
		System.out.println("\t\tSetting date created: " + flickrDf.format(createDate));
		System.out.println("\t\tSetting date posted: " + flickrDf.format(postedDate));
		System.out.println("\t\tSetting tag \"Dated\".");
		
		photoInt.setMeta(p.getId(), title, "Old Title: " + p.getTitle());
		photoInt.setDates(p.getId(), postedDate, createDate, "0");
		String[] newTag = {"Dated"};
		photoInt.addTags(p.getId(), newTag);
		
//		System.out.println("\t\tAdding photo to \"All\" set.");
//		PhotosetsInterface setsInt = flickr.getPhotosetsInterface();
//		setsInt.addPhoto("72157626349047087", p.getId());
		System.out.println("\t\tCompleted updating meta information.");
		
	}
	
	public static void main(String[] args) {
		
		FlickrDatr datr = new FlickrDatr("47213205@N04");
		datr.processAllFiles();
	}

}
